home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Documentation / Apple Event Registry / AE Suites Under Development / Word Services SDK 1.0 / Writeswell Jr. Source / DoChecking.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-25  |  12.9 KB  |  557 lines  |  [TEXT/KAHL]

  1. /* DoChecking.c
  2.  * Functions that actually do the calls to the Word Services servers.
  3.  * ©1992 Working Software, Inc.
  4.  * This source code is copyrighted.  Permission is granted to use the Word Services
  5.  * portion of the Writeswell Jr. source code in your own programs, but you 
  6.  * may not distribute the Writeswell Jr. word-processor code as a 
  7.  * commercial product.  If you modify the code, please do not call it 
  8.  * Writeswell Jr. (or Writeswell.)  This will ensure that people understand the 
  9.  * program and don’t have to deal with a number of different versions with 
  10.  * who-knows-what going on in the code.
  11.  * 
  12.  * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
  13.  * 28 Dec 91 Mike Crawford
  14.  */
  15.  
  16. #include <Aliases.h>
  17. #include <Processes.h>
  18. #include <AppleEvents.h>
  19. #include <AEObjects.h>
  20. #include <AEPackObject.h>
  21. #include <AERegistry.h>
  22. #include "TBConstants.h"
  23. #include "TBGlobals.h"
  24. #include "WordServices.h"
  25. #include "AppEvents.h"
  26. #include "ObWind.h"
  27. #include "ObText.h"
  28. #include "Gripe.h"
  29. #include "Prefs.h"
  30. #include "DoChecking.h"
  31. #include "FindProcess.h"
  32. #include "TableCheck.h"
  33.  
  34. #define LAUNCH_BY_EVENT            /* Undef this to use Proc Mgr instead of Finder AE */
  35.  
  36. OSErr LaunchSpeller( AliasHandle aliasHdl );
  37.  
  38. OSErr DoSpellCheck( short serviceNumber )
  39. {
  40.     OSErr            err;
  41.     AEDesc            docSpecifier;
  42.     AEDesc            textDescriptor;
  43.     AEDesc            textSpecifier;
  44.     AEAddressDesc    spellerAddr;
  45.     AppleEvent        btchEvent;
  46.     AppleEvent        replyEvent;
  47.     WWJrPrefsHdl    prefHdl;
  48.     ServiceType        servType;
  49.  
  50.     prefHdl = GetPrefHandle();
  51.     if ( !prefHdl ){
  52.         Gripe( "\pCannot get preferences handle" );
  53.         return resNotFound;
  54.     }
  55.  
  56.     err = OpenSpeller( serviceNumber, &spellerAddr, &servType );
  57.     if ( err ){
  58.         Gripe( "\pOpenSpeller failed to connect with speller" );
  59.         return err;
  60.     }
  61.  
  62.     switch ( servType ){
  63.         case kBatchService:
  64.             if ( (*prefHdl)->sendByList ){
  65.                 err = DoBatchCheck( &spellerAddr );
  66.                 if ( err ){
  67.                     Gripe( "\pDoBatchCheck failed" );
  68.                     return err;
  69.                 }
  70.             }else{
  71.                 err = DoBatchTableCheck( &spellerAddr );
  72.                 if ( err ){
  73.                     Gripe( "\pDoBatchTableCheck failed" );
  74.                     return err;
  75.                 }
  76.             }
  77.             break;
  78.         case kInteractiveService:
  79.             Gripe( "\pInteractive service is not implemented yet" );
  80.             return noErr;
  81.             break;
  82.         default:
  83.             Gripe( "\pBad service type code in preferences file" );
  84.             return noErr;
  85.     }
  86.  
  87.     return noErr;
  88. }
  89.  
  90. OSErr DoBatchCheck( AEAddressDesc *spellerAddrPtr )
  91. {
  92.     OSErr            err;
  93.     AEDesc            textSpecifier;
  94.     AppleEvent        btchEvent;
  95.     AppleEvent        replyEvent;
  96.     WWJrPrefsHdl    prefHdl;
  97.     AEDescList        textSpecList;            /* 1.0d7 */
  98.     long            index;                    /* 1.0d7 */
  99.  
  100.     /* We make an object specifier that refers to _our_own_ window
  101.      */
  102.  
  103.     err = CreateTextSpecifier( 1L, 1L, &textSpecifier );
  104.     
  105.     if ( err ){
  106.         Gripe( "\pCreateTextSpecifier failed" );
  107.         return err;
  108.     }
  109.  
  110.     prefHdl = GetPrefHandle();
  111.     if ( !prefHdl ){
  112.         Gripe( "\pCannot get preferences handle" );
  113.         return resNotFound;
  114.     }
  115.     
  116.     if ( (*prefHdl)->checkSel ){
  117.         /* Make a formRange descriptor that gives the selection range */
  118.  
  119.         Gripe( "\pSelection-only checking is not yet implemented" );
  120.         return noErr;
  121.     }
  122.  
  123.     /* Create the event to send to the speller */
  124.     
  125.     err = AECreateAppleEvent( kWordServicesClass,
  126.                                 kWSBatchCheckMe,
  127.                                 spellerAddrPtr,
  128.                                 kAutoGenerateReturnID,
  129.                                 kAnyTransactionID,
  130.                                 &btchEvent );
  131.     
  132.     if ( err ){
  133.         Gripe( "\pcreate btch event failed" );
  134.         return err;
  135.     }
  136.     err = AEDisposeDesc( spellerAddrPtr );
  137.     if ( err ){
  138.         Gripe( "\pAEDisposeDesc failed" );
  139.         return err;
  140.     }
  141.  
  142. #ifdef OLD_SPEC    
  143.  
  144.     /* This was used until 1.0d6 */
  145.  
  146.     /* Insert the object specifier as the direct object of the batch event */
  147.  
  148.     err = AEPutParamDesc( &btchEvent,
  149.                             keyDirectObject,
  150.                             &textSpecifier );
  151.     if ( err ){
  152.         Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
  153.         return err;
  154.     }
  155.     err = AEDisposeDesc( &textSpecifier );
  156.     if ( err ){
  157.         Gripe( "\pAEDisposeDesc failed" );
  158.         return err;
  159.     }
  160. #else
  161.  
  162.     /* 1.0d7 This is the new way to do it - use a list of object specifiers (even if
  163.      * only one of them
  164.      */
  165.     
  166.     err = AECreateList( (Ptr)NULL, (Size)0, false, &textSpecList );
  167.     if ( err ){
  168.         Gripe( "\pAECreateList failed" );
  169.         return err;
  170.     }
  171.     
  172.     /* Put our specifier into it.  If we had multiple text blocks to check, we would
  173.      * put specifiers for each into it in turn.
  174.      * Note that we use AEPutDesc, not AEPutParamDesc, to put items into an indexed
  175.      * list.
  176.      */
  177.  
  178. #define N_TEXT_SPECS    1L /*3L    */    /* Define this to be 1 for normal checking */
  179.  
  180.     for ( index = 1L; index <= N_TEXT_SPECS; index++ ){
  181.         err = AEPutDesc( &textSpecList,
  182.                             index,
  183.                             &textSpecifier );
  184.         if ( err ){
  185.             Gripe( "\pAEPutDesc failed to put text specifier into textSpecList" );
  186.             return err;
  187.         }
  188.     }
  189.  
  190.     err = AEDisposeDesc( &textSpecifier );
  191.     if ( err ){
  192.         Gripe( "\pAEDisposeDesc failed" );
  193.         return err;
  194.     }
  195.  
  196.     /* Insert the list of object specifiers as the direct object of the batch event */
  197.  
  198.     err = AEPutParamDesc( &btchEvent,
  199.                             keyDirectObject,
  200.                             &textSpecList );
  201.     if ( err ){
  202.         Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
  203.         return err;
  204.     }
  205.     err = AEDisposeDesc( &textSpecifier );
  206.     if ( err ){
  207.         Gripe( "\pAEDisposeDesc failed" );
  208.         return err;
  209.     }
  210. #endif
  211.  
  212.     /* Send the event.  We await the reply, so that if there is a failure of some
  213.      * sort in the initial connection, we can alert the user right away.  The timeout
  214.      * value to use here should be as long as one would care to have a user wait for
  215.      * the completion of a menu command.  Since we expect that the speller is on a local
  216.      * machine in this case, and should be able to respond immediately, we just give
  217.      * a few seconds for the timeout.
  218.      *
  219.      * We should assign an idle proc to spin the cursor.  Even better would be a progress
  220.      * dialog that says "Contacting speller" or some such, with an animated display that
  221.      * shows the time elapsed relative to the total timeout, so the user will know how
  222.      * long she may have to wait
  223.      */
  224.  
  225. #define kFewSeconds 300
  226.     
  227.     err = AESend( &btchEvent,
  228.                     &replyEvent,
  229.                     kAEWaitReply + kAECanInteract + kAECanSwitchLayer,
  230.                     kAENormalPriority,
  231.                     kFewSeconds,
  232.                     (IdleProcPtr)NULL,
  233.                     (EventFilterProcPtr)NULL );
  234.     
  235.     if ( err ){
  236.         Gripe( "\psend btch event failed" );
  237.         return err;
  238.     }
  239.     err = AEDisposeDesc( &btchEvent );
  240.     if ( err ){
  241.         Gripe( "\pAEDisposeDesc failed" );
  242.         return err;
  243.     }
  244.     
  245.     /* Now the event has been sent.  There is nothing more that we have to actually do
  246.      * on our own initiative to accomplish the spelling; we just sit back and respond
  247.      * to events.  In particular, we don't remember that spelling is taking place - once
  248.      * the spelling is done, we will just start seeing events from the user (mouse and
  249.      * key clicks and so on
  250.      */
  251.     
  252.     return noErr;
  253. }
  254.  
  255. OSErr OpenSpeller( short serviceNumber,
  256.                     AEAddressDesc *spellerAddrPtr,
  257.                     ServiceType *servTypePtr )
  258. {
  259.     WWJrPrefsHdl    prefHdl;
  260.     short            servID;
  261.     AliasHandle        aliasHdl;
  262.     short            curFile;
  263.     OSType            signature;
  264.     ProcessSerialNumber psn;
  265.     ProcessInfoRec        pInfo;
  266.     OSErr            err;
  267.     
  268.     prefHdl = GetPrefHandle();
  269.     if ( !prefHdl ){
  270.         Gripe( "\pCannot get prefs handle" );
  271.         return resNotFound;
  272.     }
  273.     
  274.     servID = gServItemID[ serviceNumber - 1 ];        /* C arrays start at 0 */
  275.     
  276.     *servTypePtr = (*prefHdl)->serviceType[ servID - kServiceBaseID ];
  277.  
  278.     curFile = CurResFile();
  279.     UseResFile( gPrefFileRefNum );
  280.     
  281.     aliasHdl = (AliasHandle)GetResource( rAliasType, servID );
  282.  
  283.     UseResFile( curFile );
  284.  
  285.     if ( !aliasHdl ){
  286.         Gripe( "\pCannot get alias handle for service" );
  287.         return resNotFound;
  288.     }
  289.     
  290.     /* See if the speller is out there */
  291.     signature = (*aliasHdl)->userType;
  292.  
  293.     if ( !FindAProcess( signature, &psn, &pInfo, (FSSpecPtr)NULL, (StringPtr)NULL ) ){
  294.  
  295.         EventRecord event;
  296.         short        i;
  297.  
  298.         err = LaunchSpeller( aliasHdl );
  299.         if ( err ){
  300.             Gripe( "\pUnable to launch Word Services server" );
  301.             return err;
  302.         }
  303. #ifdef NEVER        
  304.         /* Got to sleep for a little while - otherwise the speller croaks */
  305.         for ( i = 0; i < 10; i++ )
  306.             WaitNextEvent( 0, &event, 1, (RgnHandle)NULL );
  307. #endif
  308.     }    
  309.  
  310.     err = AECreateDesc( typeApplSignature,
  311.                         (Ptr)&signature,
  312.                         sizeof( signature ),
  313.                         spellerAddrPtr );
  314.     if ( err ){
  315.         Gripe( "\pAECreateDesc failed" );
  316.         return err;
  317.     }
  318.     
  319.     return noErr;
  320. }
  321.  
  322. #ifdef LAUNCH_BY_EVENT
  323. OSErr LaunchSpeller( AliasHandle aliasHdl )
  324. {
  325.     OSErr        err;
  326.     FSSpec        spellerSpec;
  327.     Boolean        changed;
  328.     AppleEvent        launchEvent;
  329.     AppleEvent        replyEvent;
  330.     AEDesc            aliasDesc;
  331.     AEDesc            folderDesc;
  332.     FSSpec            folderSpec;
  333.     AEDesc            finderAddr;
  334.     DescType        finderSig;
  335.     AliasHandle        fAliasHdl;
  336.     AEDescList        aliasList;
  337.  
  338.     /* Make sure the speller can still be found, and get its spec */
  339.     err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
  340.     
  341.     if ( err ){
  342.         Gripe( "\pCannot locate speller" );        /* Might be user canceled AShare */
  343.         return err;
  344.     }
  345.     
  346.     if ( changed ){
  347.         ChangedResource( aliasHdl );
  348.         WriteResource( aliasHdl );
  349.     }
  350.     
  351.     /* make an alias for the parent folder */
  352.     
  353.     err = FSMakeFSSpec( spellerSpec.vRefNum,
  354.                         spellerSpec.parID,
  355.                         (StringPtr)NULL,
  356.                         &folderSpec );
  357.     if ( err ){
  358.         Gripe( "\pMakeFSSpec failed" );
  359.         return err;
  360.     }
  361.     
  362.     err = NewAlias( (FSSpecPtr)NULL, &folderSpec, &fAliasHdl );
  363.     if ( err ){
  364.         Gripe( "\pNewAlias failed" );
  365.         return err;
  366.     }
  367.  
  368.     /* Create the event to send to the Finder */
  369.     
  370.     finderSig = 'MACS';                        /* Creator code of finder; type is 'FNDR' */
  371.     err = AECreateDesc( typeApplSignature,
  372.                         (Ptr)&finderSig,
  373.                         sizeof( finderSig ),
  374.                         &finderAddr );
  375.     if ( err ){
  376.         Gripe( "\pAECreateDesc failed" );
  377.         return err;
  378.     }    
  379.                 
  380.     err = AECreateAppleEvent( kAEFinderEvents,
  381.                                 kAEOpenSelection,
  382.                                 &finderAddr,
  383.                                 kAutoGenerateReturnID,
  384.                                 kAnyTransactionID,
  385.                                 &launchEvent );
  386.     
  387.     if ( err ){
  388.         Gripe( "\pcreate open selection event failed" );
  389.         return err;
  390.     }
  391.     err = AEDisposeDesc( &finderAddr );
  392.     if ( err ){
  393.         Gripe( "\pAEDisposeDesc failed" );
  394.         return err;
  395.     }
  396.     
  397.     /* Insert the folder alias record as the direct object of the batch event */
  398.  
  399.     /* First make a descriptor of the alias */
  400.     HLock( fAliasHdl );
  401.  
  402.     err = AECreateDesc( typeAlias,
  403.                         (Ptr)*fAliasHdl,
  404.                         (*fAliasHdl)->aliasSize,
  405.                         &folderDesc );
  406.  
  407.     HUnlock( fAliasHdl );
  408.     DisposHandle( fAliasHdl );
  409.  
  410.     if ( err ){
  411.         Gripe( "\pAECreateDesc failed" );
  412.         return err;
  413.     }    
  414.     
  415.     err = AEPutParamDesc( &launchEvent,
  416.                             keyDirectObject,
  417.                             &folderDesc );
  418.     if ( err ){
  419.         Gripe( "\pAEPutParamDesc failed to put direct object on open selection event" );
  420.         return err;
  421.     }
  422.     err = AEDisposeDesc( &folderDesc );
  423.     if ( err ){
  424.         Gripe( "\pAEDisposeDesc failed" );
  425.         return err;
  426.     }
  427.  
  428.     /* Put the application alias on the event */
  429.     HLock( aliasHdl );
  430.  
  431.     err = AECreateDesc( typeAlias,
  432.                         (Ptr)*aliasHdl,
  433.                         (*aliasHdl)->aliasSize,
  434.                         &aliasDesc );
  435.  
  436.     HUnlock( aliasHdl );
  437.  
  438.     if ( err ){
  439.         Gripe( "\pAECreateDesc failed" );
  440.         return err;
  441.     }    
  442.  
  443.     /* Now make a list of the alias descriptor.  There is only one element in this
  444.      * list
  445.      */
  446.     
  447.     err = AECreateList( (Ptr)NULL, (Size)0, false, &aliasList );
  448.     
  449.     if ( err ){
  450.         Gripe( "\pAECreateList failed" );
  451.         return err;
  452.     }
  453.     
  454.     err = AEPutDesc( &aliasList, 1L, &aliasDesc );
  455.     
  456.     if ( err ){
  457.         Gripe( "\pAEPutDesc failed to put alias into alias list" );
  458.         return err;
  459.     }
  460.  
  461.     err = AEDisposeDesc( &aliasDesc );
  462.     if ( err ){
  463.         Gripe( "\pAEDisposeDesc failed" );
  464.         return err;
  465.     }
  466.     
  467.     err = AEPutParamDesc( &launchEvent,
  468.                             keySelection,
  469.                             &aliasList );
  470.     if ( err ){
  471.         Gripe( "\pAEPutParamDesc failed to put keySelection on open selection event" );
  472.         return err;
  473.     }
  474.  
  475.     err = AEDisposeDesc( &aliasList );
  476.     if ( err ){
  477.         Gripe( "\pAEDisposeDesc failed" );
  478.         return err;
  479.     }
  480.  
  481. #define kFewSeconds 300
  482.     
  483.     err = AESend( &launchEvent,
  484.                     &replyEvent,
  485.                     kAEWaitReply + kAECanInteract,        /* Don't allow later switch */
  486.                     kAENormalPriority,
  487.                     kFewSeconds,
  488.                     (IdleProcPtr)NULL,
  489.                     (EventFilterProcPtr)NULL );
  490.     
  491.     if ( err ){
  492.         Gripe( "\psend open selection event failed" );
  493.         return err;
  494.     }
  495.     err = AEDisposeDesc( &launchEvent );
  496.     if ( err ){
  497.         Gripe( "\pAEDisposeDesc failed" );
  498.         return err;
  499.     }
  500.     
  501.     return noErr;
  502. }
  503. #else
  504.  
  505. /* This makes the speller fail to process the batch event - I don't know why */
  506.  
  507. OSErr LaunchSpeller( AliasHandle aliasHdl )
  508. {
  509.     LaunchParamBlockRec    pb;
  510.     OSErr        err;
  511.     FSSpec        spellerSpec;
  512.     Boolean        changed;
  513.     char        *cPtr;
  514.     short        i;
  515.     
  516.     /* Make sure the speller can still be found */
  517.     err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
  518.     
  519.     if ( err ){
  520.         Gripe( "\pCannot locate speller" );        /* Might be user canceled AShare */
  521.         return err;
  522.     }
  523.     
  524.     if ( changed ){
  525.         ChangedResource( aliasHdl );
  526.         WriteResource( aliasHdl );
  527.     }
  528.     
  529.     cPtr = (char*)&pb;
  530.     
  531.     for ( i = 0; i < sizeof( pb ); i++ ){
  532.         *cPtr++ = 0;
  533.     }
  534.  
  535.     pb.launchBlockID = extendedBlock;
  536.     pb.launchEPBLength = extendedBlockLen;
  537.     pb.launchControlFlags = launchNoFileFlags + launchContinue /*+ launchDontSwitch*/;
  538.     pb.launchAppSpec = &spellerSpec;
  539.     pb.launchAppParameters = NULL;
  540.     
  541.     err = LaunchApplication( &pb );
  542.     
  543.     if ( err == memFullErr ){
  544.     
  545.         Gripe( "\pThere is not enough memory to launch the Word Services server" );
  546.         return err;
  547.     }
  548.     
  549.     if ( err ){
  550.         Gripe( "\pUnable to launch the Word Services server" );
  551.         return err;
  552.     }
  553.  
  554.     return noErr;
  555. }
  556.  
  557. #endif /* LAUNCH_BY_EVENT */